/*
 * Copyright Eugen Stoian <stoian.e@gmail.com> 2010
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "Scanner.h"
#include <QString>
#include <QTextStream>
#include <QtDebug>

static bool isSymbol(const QChar& c)
{
    return (c=='<')||
           (c=='>')||
           (c=='!')||
           (c=='+')||
           (c=='-')||
           (c=='*')||
           (c=='/')||
           (c=='^')||
           (c=='=')||
           (c==':')||
           (c=='?')||
           (c=='@')||
           (c=='#')||
           (c=='$')||
           (c=='%')||
           (c=='&')||
           (c=='|')||
           (c=='~')||
           (c=='\\');
}

Scanner::Scanner(QTextStream & anInputStream)
    :_inputStream(anInputStream),_linePos(0),_charPos(0)
{
}

Token Scanner::scan()
{
    static QChar lastChar = ' ';
    static int line = 1;
    static int index = 0;
    QString tokenString;

    while (lastChar.isSpace()){
        if(lastChar=='\n')
        {
            ++line;
            index = 0;
        }
        _inputStream >> lastChar;
        ++index;
    }
    if (lastChar.isLetter()) {
        int relindex = 0;
        do{
            tokenString += lastChar;
            ++relindex;
            _inputStream >> lastChar;
        } while (lastChar.isLetterOrNumber());
        index+=relindex;
        if(tokenString=="def")
            return Token(tokenString,Token::Keyword,line,index-relindex);
        return Token(tokenString,Token::Identifier,line,index-relindex);
    }

    if (lastChar.isDigit() || lastChar == '.') {
        int relindex = 0;
        do {
          tokenString += lastChar;
          ++relindex;
          _inputStream >> lastChar;
        } while (lastChar.isDigit() || lastChar == '.');
        index+=relindex;
        return Token(tokenString,Token::Number,line,index-relindex);
    }
    if(lastChar == '"')
    {

        int relindex = 0;
        _inputStream >> lastChar;
        do{
            tokenString += lastChar;
            ++relindex;
            _inputStream >> lastChar;
        } while (lastChar!='"');
        index+=relindex;
        _inputStream >> lastChar;
        ++index;
        return Token(tokenString,Token::Text,line,index-relindex-1);
    }
    if(lastChar == '(')
    {
        ++index;
        _inputStream >> lastChar;
        return Token("(",Token::LParen,line,index-1);
    }

    if(lastChar == ')')
    {
        ++index;
        _inputStream >> lastChar;
        return Token(")",Token::RParen,line,index-1);
    }

    if(lastChar == '[')
    {
        ++index;
        _inputStream >> lastChar;
        return Token("[",Token::LBracket,line,index-1);
    }

    if(lastChar == ']')
    {
        ++index;
        _inputStream >> lastChar;
        return Token("]",Token::RBracket,line,index-1);
    }

    if(lastChar == '{')
    {
        ++index;
        _inputStream >> lastChar;
        return Token("{",Token::LBrace,line,index-1);
    }

    if(lastChar == '}')
    {
        ++index;
        _inputStream >> lastChar;
        return Token("}",Token::RBrace,line,index-1);
    }

    if(lastChar == ',')
    {
        ++index;
        _inputStream >> lastChar;
        return Token(",",Token::Comma,line,index-1);
    }

    if(lastChar == ';')
    {
        ++index;
        _inputStream >> lastChar;
        return Token(";",Token::Semicolon,line,index-1);
    }

    if (isSymbol(lastChar)){
        int relindex = 0;
        do{
            tokenString += lastChar;
            ++relindex;
            _inputStream >> lastChar;
        } while(isSymbol(lastChar));

        index+=relindex;
        return Token(tokenString,Token::Operator,line,index-relindex);
    }

    if (_inputStream.atEnd())
        return Token(QString(),Token::Eof,line,index);

    return Token(QString(),Token::Unknown,line,index);
}
